package com.woniu108.person.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sun.org.apache.xpath.internal.functions.WrongNumberArgsException;
import com.woniu108.carService.commons.log.AdminHistoryLog;
import com.woniu108.carService.commos.dto.AccountDto;
import com.woniu108.carService.commos.dto.UserInfoDto;
import com.woniu108.carService.commos.dto.UserSimpleDto;
import com.woniu108.carService.commos.exception.WoniuException;
import com.woniu108.carService.commos.model.Result;
import com.woniu108.carService.commos.util.JWTUtil;
import com.woniu108.carService.commos.util.RedisUtil;
import com.woniu108.carService.commos.util.StaticData;
import com.woniu108.person.client.ValueAddedClient;
import com.woniu108.person.form.*;
import com.woniu108.person.model.AdminInfo;
import com.woniu108.person.model.AdminRole;
import com.woniu108.person.model.StoreAdmin;
import com.woniu108.person.model.UserInfo;
import com.woniu108.person.param.*;
import com.woniu108.person.service.AdminInfoService;
import com.woniu108.person.service.AdminRoleService;
import com.woniu108.person.service.StoreAdminService;
import com.woniu108.person.service.UserInfoService;
import com.woniu108.valueAdded.form.ScoreRecordsForm;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author yanxi
 * @since 2024-05-23
 */
@RestController
@RequestMapping("/userInfo")
@Api(tags = "用户信息接口")
public class UserInfoController {

    @Resource
    private UserInfoService userInfoService;
    @Resource
    private AdminInfoService adminInfoService;
    @Resource
    private StoreAdminService storeAdminService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ValueAddedClient valueAddedClient;
    @Resource
    private AdminRoleService adminRoleService;

    public String getAdminId(String token){
        String refreshToken=redisUtil.getString(token);
        String adminId=JWTUtil.parseAdminToken(refreshToken).get("adminId").toString();
        return adminId;
    }
    public String getUserId(String token){
        String refreshToken=redisUtil.getString(token);
        String userId=JWTUtil.parseUserToken(refreshToken).get("userId").toString();
        return userId;
    }

    public String getStoreAdminId(String token){
        String refreshToken=redisUtil.getString(token);
        String storeAdminId=JWTUtil.parseStoreAdminToken(refreshToken).get("storeAdminId").toString();
        return storeAdminId;
    }

    public static int getAge(String idCard) {    //身份证年龄获取
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); // 根据身份证格式设置日期格式化模式
        String birthdayStr = idCard.substring(6, 14); // 获取生日部分字符串
        int year = Integer.parseInt(birthdayStr.substring(0, 4));
        int month = Integer.parseInt(birthdayStr.substring(4, 6));
        int day = Integer.parseInt(birthdayStr.substring(6, 8));
        LocalDate birth = LocalDate.of(year, month, day);
        LocalDate now = LocalDate.now();
        int age = Period.between(birth, now).getYears();
        System.out.println("年龄：" + age);
        return age;
    }
    /**
     * 根据筛选信息查找单个用户
     * @param form 单一用户筛选信息 昵称 真实姓名 手机号
     * @return  UserInfoDto 用户详细信息
     */
    @PostMapping("/getOneUser.c")
    @ApiOperation("根据筛选信息查找单个用户")
    public Result<UserInfoDto> getOneUser(@RequestBody GetOneUserForm form){
        GetOneUserParam param = BeanUtil.toBean(form, GetOneUserParam.class);
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        if(ObjectUtil.isNotEmpty(param.getUserPhone())) wrapper.eq("user_phone",param.getUserPhone());
        if(ObjectUtil.isNotEmpty(param.getUserNickName())) wrapper.like("user_nick_name",param.getUserNickName());
        if(ObjectUtil.isNotEmpty(param.getUserRealName())) wrapper.like("user_real_name",param.getUserRealName());
        UserInfo userInfo = userInfoService.getOne(wrapper);
        UserInfoDto dto = BeanUtil.toBean(userInfo, UserInfoDto.class);
        return Result.getResult(UserInfoDto.class).setData(dto);
    }

    /**
     * 根据id查找单个用户
     * @param userId 用户ID
     * @return UserInfoDto 用户详细信息
     */
    @GetMapping("/getByUserId/{userId}.c")
    @ApiOperation("根据id查找单个用户")
    @ApiImplicitParam(name = "userId",value ="用户ID" )
    public Result<UserInfoDto> getByUserId(@PathVariable("userId")String userId){
        UserInfo userInfo = userInfoService.getById(userId);
        if(ObjectUtil.isEmpty(userInfo)) throw new WoniuException("用户不存在",10001);
        if(userInfo.getUserState()==StaticData.USER_STATE_DELETE) throw new WoniuException("用户状态异常",10001);
        UserInfoDto dto = BeanUtil.toBean(userInfo, UserInfoDto.class);
        return Result.getResult(UserInfoDto.class).setData(dto);
    }

    /**
     * 筛选获取用户列表
     * @param form 用户列表筛选信息 昵称 姓名 手机号 状态 页码 每页信息数
     * @return Page<UserInfoDto> 单页用户详细信息列表
     */
    @PostMapping("/allUserList.api")
    @ApiOperation("根据筛选条件获取用户列表")
    public Result<Page<UserInfoDto>> allUserList(@RequestBody UserListForm form){
        UserListParam param = BeanUtil.toBean(form, UserListParam.class);
        Page<UserInfoDto> page=userInfoService.allUserList(param);
        return Result.newPageInstance(UserInfoDto.class).setData(page);
    }

    /**
     * 禁言用户
     * @param userId 用户ID
     * @return
     */
    @GetMapping("/disabledUser.api")
    @ApiOperation("禁言用户")
    @ApiImplicitParam(name = "userId",value ="用户ID" )
    @AdminHistoryLog
    public Result disabledUser(String userId){
        UserInfo userInfo = userInfoService.getById(userId);
        if(userInfo.getUserState()!= StaticData.USER_STATE_NORMAL) throw new WoniuException("用户状态异常",10001);
        userInfo.setUserState(StaticData.USER_STATE_NOTALK);
        userInfoService.updateById(userInfo);
        return Result.getResult().setMsg("禁言成功");
    }

    /**
     * 用户解禁
     * @param userId
     * @return result 接口是否正常访问到结果
     */
    @GetMapping("/ableUser.api")
    @ApiOperation("用户解禁")
    @ApiImplicitParam(name = "userId",value ="用户ID" )
    @AdminHistoryLog
    public Result ableUser(String userId){
        UserInfo userInfo = userInfoService.getById(userId);
        if(userInfo.getUserState()!= StaticData.USER_STATE_NOTALK) throw new WoniuException("用户状态异常",10001);
        userInfo.setUserState(StaticData.USER_STATE_NORMAL);
        userInfoService.updateById(userInfo);
        return Result.getResult().setMsg("解禁成功");
    }


    /**
     * 用户积分增加并记录到log
     * @param userId 用户ID
     * @param score 变动积分
     * @return newScore 变动后积分
     */
    @GetMapping("/addUserScore.c")
    @ApiOperation("增加用户积分")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId",value ="用户ID" ),
            @ApiImplicitParam(name = "score",value ="变动积分" ),
            @ApiImplicitParam(name = "scoreType",value ="积分类型(购物、签到)" )
    })
    public Result<Integer> addUserScore(String userId,Integer score,Integer scoreType){
        UserInfo userInfo = userInfoService.getById(userId);
        BigDecimal newScore = userInfo.getScore().add(BigDecimal.valueOf(score));
        userInfo.setScore(newScore);
        userInfoService.updateById(userInfo);
        //记录积分操作历史
        ScoreRecordsForm form = new ScoreRecordsForm();
        form.setScoreType(scoreType);
        form.setModifyed(StaticData.SCORE_ADD);
        form.setUserId(userId);
        form.setScore(newScore.intValue());
        Result result = valueAddedClient.addOrReduceScoreRecords(form);
        if(result.getCode()!=200) throw new WoniuException(result.getMsg(),result.getCode());
        return Result.getResult(Integer.class).setData(newScore.intValue()).setMsg("增加成功");
    }

    /**
     * 用户积分减少并记录到log
     * @param userId 用户ID
     * @param score 变动积分
     * @return newScore变动后积分
     */
    @GetMapping("/reduceUserScore.c")
    @ApiOperation("减少用户积分")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId",value ="用户ID" ),
            @ApiImplicitParam(name = "score",value ="变动积分" ),
            @ApiImplicitParam(name = "scoreType",value ="积分类型(购物、签到)" )
    })
    public Result<Integer> reduceUserScore(String userId,Integer score,Integer scoreType){
        UserInfo userInfo = userInfoService.getById(userId);
        BigDecimal newScore = userInfo.getScore().subtract(BigDecimal.valueOf(score));
        if(newScore.compareTo(BigDecimal.ZERO)<0) throw new WoniuException("积分不足",10001);
        userInfo.setScore(newScore);
        userInfoService.updateById(userInfo);
        ScoreRecordsForm form = new ScoreRecordsForm();
        form.setScoreType(scoreType);
        form.setModifyed(StaticData.SCORE_REDUCE);
        form.setUserId(userId);
        form.setScore(newScore.intValue());
        Result result = valueAddedClient.addOrReduceScoreRecords(form);
        if(result.getCode()!=200) throw new WoniuException(result.getMsg(),result.getCode());
        return Result.getResult(Integer.class).setData(newScore.intValue()).setMsg("增加成功");
    }


    /**
     * 根据id获取具体角色信息
     * @param id 模糊ID 可能是用户、管理员、门店管理员的ID
     * @return AccountDto 模糊账号信息 账号的ID 账号对应权限 账号所有人的名称(若为用户则展示昵称)
     */
    @GetMapping("/getByCommonId/{id}.c")
    @ApiOperation("根据ID获取用户或管理员信息")
    @ApiImplicitParam(name = "id",value ="ID" )
    public Result<AccountDto> getByCommonId(@PathVariable("id") String id){
        AccountDto accountDto = new AccountDto();
        accountDto.setAccountId(id);
        UserInfo userInfo = userInfoService.getById(id);
        if(ObjectUtil.isNotEmpty(userInfo)){
            accountDto.setAccountRoleName("普通用户");
            accountDto.setAccountName(userInfo.getUserNickName());
        }
        AdminInfo adminInfo = adminInfoService.getById(id);
        if(ObjectUtil.isNotEmpty(adminInfo)){
            Integer adminRoleId = adminInfo.getAdminRoleId();
            AdminRole adminRole = adminRoleService.getById(adminRoleId);
            accountDto.setAccountRoleName(adminRole.getAdminRoleName());
            accountDto.setAccountName(adminInfo.getAdminName());
        }
        StoreAdmin storeAdmin = storeAdminService.getById(id);
        if(ObjectUtil.isNotEmpty(storeAdmin)){
            accountDto.setAccountName("门店管理员");
            accountDto.setAccountName(storeAdmin.getStoreAdminName());
        }
        if(ObjectUtil.isEmpty(accountDto)) throw new WoniuException("该id无效",10001);
        return Result.getResult(AccountDto.class).setData(accountDto);
    }

    /**
     * 发送手机验证码
     * @param phone 手机号码
     * @return result 接口是否正常访问到结果
     */
    @GetMapping("/sendCheckMessage")
    @ApiOperation("发送手机验证码")
    @ApiImplicitParam(name = "phone",value ="手机号码" )
    public Result sendCheckMessage(String phone){
        //直接调用admin方法接口，发送验证手机验证码通用
        adminInfoService.sendCheckMessage(phone);
        return Result.getResult().setMsg("发送短信成功");
    }

    /**
     * 验证手机验证码
     * @param form 手机号 验证码
     * @return result 接口是否正常访问到结果
     */
    @PostMapping("/checkMessage")
    @ApiOperation("验证手机验证码")
    public Result checkMessage(@RequestBody CheckMessageForm form){
        CheckMessageParam param = BeanUtil.toBean(form, CheckMessageParam.class);
        adminInfoService.checkMessage(param);
        return Result.getResult().setMsg("验证码验证通过");
    }
    /**
     * 手机验证码注册，返回userInfoDto信息
     * @param form 用户注册信息
     * @param br 参数校验错误信息
     * @return UserInfoDto 用户详细信息
     */
    @PostMapping("/registerUserByCode")
    @ApiOperation("手机验证码注册")
    public Result<UserInfoDto> registerUser(@RequestBody @Valid RegisterUserForm form, BindingResult br){
                if (br.hasErrors()) {//如果校验没有通过，返回true
                    List<ObjectError> allErrors = br.getAllErrors();
                    //将所有校验未通过的错误信息转换为JSON字符串返回到错误信息中
                    throw new WoniuException(JSONUtil.toJsonStr(allErrors),10001);
                }
//        if (br.hasErrors()) throw new ParameterValidException(30001,"参数校验失败");
        System.out.println("form:"+form);
        String cardNum = form.getCardNum();
        int age = getAge(cardNum);
        if(age<18) throw new WoniuException("未满18岁，不可注册",10001);
        RegisterUserParam param = BeanUtil.toBean(form, RegisterUserParam.class);
        CheckMessageForm messageForm = new CheckMessageForm();
        messageForm.setCode(param.getCode());
        messageForm.setMobile(param.getUserPhone());
        Result result = this.checkMessage(messageForm);
        System.out.println("result:"+result);
        if(result.getCode()!=200) throw new WoniuException(result.getMsg(), result.getCode());
        UserInfo userInfo=BeanUtil.toBean(param,UserInfo.class);
        String random=new Snowflake(1,1).nextIdStr();
        userInfo.setUserId(random);
        userInfo.setUserState(StaticData.USER_STATE_NORMAL);
        userInfo.setScore(BigDecimal.valueOf(0));
        userInfo.setCreateTime(LocalDateTime.now());
        userInfoService.save(userInfo);
        UserInfoDto userInfoDto = BeanUtil.toBean(userInfo, UserInfoDto.class);
        return Result.getResult(UserInfoDto.class).setMsg("用户注册成功").setData(userInfoDto);
    }

    /**
     * 验证码用户登录
     * @param form 用户手机验证码登录信息
     * @param response
     * @return UserSimpleDto 用户登录返回信息
     */
    @PostMapping("/userCodeLogin")
    @ApiOperation("用户手机号验证码登录")
    public Result<UserSimpleDto> userCodeLogin(@RequestBody UserCodeLoginForm form, HttpServletResponse response){
        CheckMessageForm form1=new CheckMessageForm();
        form1.setCode(form.getCode());
        form1.setMobile(form.getUserPhone());
        AdminInfoController adminInfoController=new AdminInfoController();
        Result result = adminInfoController.checkMessage(form1);
        if(result.getCode()!=200) throw new WoniuException(result.getMsg(), result.getCode());
        UserCodeLoginParam param=BeanUtil.toBean(form,UserCodeLoginParam.class);
        UserSimpleDto dto=userInfoService.userCodeLogin(param.getUserPhone());
        //更新双token
        Map<String, Object> map = BeanUtil.beanToMap(dto);
        HashMap<String,Object> accessBody=new HashMap<String,Object>();
        String random=new Snowflake(1,1).nextIdStr();
        accessBody.put("random",random);
        String accessToken= JWTUtil.createUserToken(accessBody,60);//短token,有效时间60分钟
        String refreshToken=JWTUtil.createUserToken(map,3*24*60);//长token，有效时间3天
        //保存长token到Redis
        redisUtil.setString(accessToken,refreshToken,3*24*60*60);
        //响应到前端,设置响应头,这里使用的是短token
        response.setHeader("token",accessToken);
        response.setHeader("Access-Control-Expose-Headers","token");
        return Result.getResult(UserSimpleDto.class).setMsg("登录成功").setData(dto);
    }

    /**
     * 用户手机账号密码登录
     * @param form 用户手机账号密码登录信息
     * @param response
     * @return  UserSimpleDto 用户登录返回信息
     */
    @PostMapping("/userLogin")
    @ApiOperation("用户手机账号密码登录")
    public Result<UserSimpleDto> userLogin(@RequestBody UserLoginForm form,HttpServletResponse response){
        UserLoginParam param=BeanUtil.toBean(form,UserLoginParam.class);
        UserSimpleDto dto=userInfoService.userLogin(param);
        //更新双token
        Map<String, Object> map = BeanUtil.beanToMap(dto);
        HashMap<String,Object> accessBody=new HashMap<String,Object>();
        String random=new Snowflake(1,1).nextIdStr();
        accessBody.put("random",random);
        String accessToken= JWTUtil.createUserToken(accessBody,60);//短token,有效时间60分钟
        String refreshToken=JWTUtil.createUserToken(map,3*24*60);//长token，有效时间3天
        //保存长token到Redis
        redisUtil.setString(accessToken,refreshToken,3*24*60*60);
        //响应到前端,设置响应头,这里使用的是短token
        response.setHeader("token",accessToken);
        response.setHeader("Access-Control-Expose-Headers","token");
        return Result.getResult(UserSimpleDto.class).setMsg("登录成功").setData(dto);
    }

    /**
     * 更新用户优惠券信息
     * @param userId 用户ID
     * @param details 用户优惠券信息(JSON)
     * @return result 接口是否正常访问到结果
     */
    @GetMapping("/updateTicketDetails.c")
    @ApiOperation("更新用户优惠券信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId",value ="用户ID" ),
            @ApiImplicitParam(name = "details",value ="用户优惠券信息(JSON)" )
    })
    public Result updateTicketDetails(String userId,String details){
        UserInfo userInfo = userInfoService.getById(userId);
        if(ObjectUtil.isEmpty(userInfo)) throw new WoniuException("用户不存在",10001);
        userInfo.setTicketDetails(details);
        userInfoService.updateById(userInfo);
        return Result.getResult().setMsg("更新用户优惠券信息成功");
    }

    /**
     * 根据token信息获取模糊账号信息
     * @param token
     * @return  AccountDto 账户模糊信息
     */
    @GetMapping("/checkRole.c")
    @ApiOperation("获取账号模糊信息")
    public Result<AccountDto> checkRole(@RequestHeader String token){
        String userId = null;
        String adminId = null;
        try {
            userId = this.getUserId(token);
            adminId = this.getAdminId(token);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
        if(userId!=null) {
            Result<AccountDto> result = this.getByCommonId(userId);
            if(result.getCode()!=200) throw new WoniuException(result.getMsg(),result.getCode());
            return result;
        }else if(adminId!=null){
            Result<AccountDto> result = this.getByCommonId(adminId);
            if(result.getCode()!=200) throw new WoniuException(result.getMsg(),result.getCode());
            return result;
        }else{
            throw new WoniuException("身份有误,非用户或管理员",10001);
        }
        }
    }

    /**
     * 根据token获取用户信息
     * @param token
     * @return UserInfoDto 用户详细信息
     */
    @GetMapping("/loadUserInfo")
    @ApiOperation("根据token获取用户信息")
    public Result<UserInfoDto> loadUserInfo(@RequestHeader String token){
        String userId = this.getUserId(token);
        UserInfo userInfo = userInfoService.getById(userId);
        if(userId==null||ObjectUtil.isEmpty(userInfo)) throw new WoniuException("用户信息不存在",10001);
        if(userInfo.getUserState()==StaticData.USER_STATE_DELETE) throw new WoniuException("账号状态异常",10001);
        UserInfoDto dto = BeanUtil.toBean(userInfo, UserInfoDto.class);
        return Result.getResult(UserInfoDto.class).setData(dto);
    }
}

